package com.jsbs.iam.user.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jsbs.iam.common.core.dto.Result;
import com.jsbs.iam.common.core.utils.PageHelperTool;
import com.jsbs.iam.user.constant.RedisConstants;
import com.jsbs.iam.user.dto.ApplyTypeAddDto;
import com.jsbs.iam.user.dto.ApplyTypeDeleteDto;
import com.jsbs.iam.user.dto.ApplyTypeSelectDto;
import com.jsbs.iam.user.entity.IamApplyTypeBase;
import com.jsbs.iam.user.feign.IdentFeignInterface;
import com.jsbs.iam.user.mapper.ApplyTypeMapper;
import com.jsbs.iam.user.mapper.UserInfoMapper;
import com.jsbs.iam.user.service.ApplyTypeService;
import com.jsbs.iam.user.vo.ApplyTypeDetailVo;
import com.jsbs.iam.user.vo.ApplyTypeInfoVo;
import com.jsbs.iam.user.vo.RelevancyApplyVo;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @BelongsProject: iam
 * @BelongsPackage: com.jsbs.iam.user.service.impl
 * @Author: WangJiYuan
 * @Description: TODO
 * @Version: 2023-01-03  14:02
 */
@Slf4j
@Service
public class ApplyTypeServiceImpl implements ApplyTypeService {

    private static final Logger logger = LoggerFactory.getLogger(ApplyTypeServiceImpl.class);


    @Autowired
    private ApplyTypeMapper applyTypeMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Resource
    private RedissonClient redissonClient;

    @Autowired
    private IdentFeignInterface identFeignInterface;

    private static final String ADMIN_USER = "admin";

    @Override
    public List<RelevancyApplyVo> getRelevancyApply(String companyCode) {
        return applyTypeMapper.getRelevancyApply(companyCode);
    }


    public String getApplyTypeCodeByRedis(String prefix, int numLength, String companyCode) {
        // 生成应用类型编码加锁，失效时间10分钟
        RLock lock = redissonClient.getLock(RedisConstants.APPLY_TYPE_CODE_LOCK);
        String returnCode="";
        try {
            String upperCode ="";
            //Redis中存储的key
            String key = "apply_" + prefix;
            Long size = redisTemplate.opsForList().size(key);//查找 prefix 的key值的数据长度
            if (size > 0) {//有数据
                List leve = redisTemplate.opsForList().range(key, 0, -1);//获取该key下面的所有值(-1 所有的值，；1下一个值
                upperCode = leve.get(leve.size() - 1).toString();//返回最后一个值
            }
            //判断redis中序列是否为空
            if (StringUtils.isEmpty(upperCode)) {
                //查询应用类型编码
                upperCode = applyTypeMapper.selectApplyTypeId(companyCode);
            }
            int Suffix;  //后缀数字
            if (!StringUtil.isNullOrEmpty(upperCode)) { //有数据
                String sequence = upperCode.substring(prefix.length());//截取前缀开始的后面的数字
                Suffix = Integer.parseInt(sequence);
                Suffix++;//最后的序号加一
            } else {
                Suffix = 1;//没有数据
            }
            returnCode = prefix + String.format("%0" + numLength + "d", Suffix);//后缀不够numLength长，前面补充0
            redisTemplate.opsForList().rightPush(key, returnCode);//存入Redis
        } catch (Exception e) {
            log.error("Route=>ApplyTypeServiceImpl method=>getApplyTypeCodeByRedis 应用类型,系统自动生成编码失败:", e);
            throw new RuntimeException("应用类型,系统自动生成编码异常");
        } finally {
            // 手动解锁
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
        return  returnCode;
    }

    @Override
    public List<String> verifyOrgType(List<String> orgCodes, String companyCode) {
        return userInfoMapper.verifyOrgType(orgCodes, companyCode);
    }


    @Override
    @Transactional
    public void insetApplyTypeInfo(ApplyTypeAddDto applyTypeAddDto) {
        //系统生成应用类型编码
        applyTypeAddDto.setApplyTypeCode(this.getApplyTypeCodeByRedis("yylxbm",6,applyTypeAddDto.getCompanyCode()));
        //新增应用类型基础数据
        applyTypeMapper.insetApplyTypeMainData(applyTypeAddDto);
        //新增应用类型与组织数据
        applyTypeMapper.insetApplyTypeOrgInfo(applyTypeAddDto);
        //新增关联应用数据
        if (CollectionUtils.isNotEmpty(applyTypeAddDto.getApplyCodes())) {
            applyTypeMapper.updateRelevancyApplyData(applyTypeAddDto);
        }
    }

    @Override
    public PageInfo getApplyTypeInfo(ApplyTypeSelectDto applyTypeSelectDto) {
        applyTypeSelectDto.init();
        PageHelper.startPage(applyTypeSelectDto.getCurrPage(), applyTypeSelectDto.getPageSize());
        //查询应用类型数据
        //List<ApplyTypeInfoVo> list = applyTypeMapper.getApplyTypeInfo(applyTypeSelectDto);
        List<ApplyTypeInfoVo> list = new ArrayList<>();
        //权限限制
        if (ADMIN_USER.equals(applyTypeSelectDto.getCreatePerson())) {
            //超管
            list = applyTypeMapper.getApplyTypeInfo(applyTypeSelectDto);
        } else {
            //普管
            //通过角色编码查询应用类型编码
            List<String> applyTypeCodes = applyTypeMapper.getAdminRoleApplyTypeCodes(applyTypeSelectDto);
            applyTypeSelectDto.setApplyTypeCodes(applyTypeCodes);
            //获取普通管理员的应用类型数据
            list = applyTypeMapper.getAdminRoleApplyTypeData(applyTypeSelectDto);
        }
        PageInfo<ApplyTypeInfoVo> page = new PageInfo<>(list);
        PageInfo<ApplyTypeInfoVo> pageInfo =
                PageHelperTool.initPageInfoObj(applyTypeSelectDto.getCurrPage(), (int) page.getTotal(), applyTypeSelectDto.getPageSize(), page);
        return pageInfo;
    }

    @Override
    public int verifyApplyTypeName(String applyTypeName, String companyCode) {
        return applyTypeMapper.verifyApplyTypeName(applyTypeName,companyCode);
    }

    @Override
    public ApplyTypeDetailVo getApplyTypeDetail(String applyTypeCode, String companyCode) {
        ApplyTypeDetailVo detailVo = new ApplyTypeDetailVo();
        //查询应用类型主数据
        IamApplyTypeBase applyTypeBase = applyTypeMapper.getApplyTypeBase(applyTypeCode,companyCode);
        //查询应用类型对应的组织数据
        List<String> orgCodes = applyTypeMapper.selectApplyTypeOrg(applyTypeCode,companyCode);
        //查询应用类型关联应用数据
        List<String> applyCodes = applyTypeMapper.selectRelevancyApply(applyTypeCode,companyCode);

        //组装vo数据
        detailVo.setApplyTypeCode(applyTypeBase.getApplyTypeCode());
        detailVo.setApplyTypeName(applyTypeBase.getApplyTypeName());
        detailVo.setApplyUrl(applyTypeBase.getApplyUrl());
        detailVo.setApplyTypeRemark(applyTypeBase.getApplyTypeRemark());
        detailVo.setOrgCodes(orgCodes);
        detailVo.setApplyCodes(applyCodes);
        return detailVo;
    }

    @Override
    public String getApplyTypeName(String applyTypeCode, String companyCode) {
        return applyTypeMapper.getApplyTypeName(applyTypeCode,companyCode);
    }

    @Override
    @Transactional
    public void updateApplyTypeInfo(ApplyTypeAddDto applyTypeAddDto) {
        //修改应用类型基础数据
        applyTypeMapper.updateApplyTypeMainData(applyTypeAddDto);
        //清除原有应用类型和组织的关系
        //  TODO  wjy  这里现在只能彻底删除数据  不能逻辑删除
        applyTypeMapper.clearApplyTypeOrgInfo(applyTypeAddDto);
        //重新维护应用类型与组织关系数据
        applyTypeMapper.insetApplyTypeOrgInfo(applyTypeAddDto);
        //修改关联应用数据
        //清除原有关联应用数据
        applyTypeMapper.clearRelevancyApplyData(applyTypeAddDto);
        if (CollectionUtils.isNotEmpty(applyTypeAddDto.getApplyCodes())) {
            //重新维护关联应用数据
            applyTypeMapper.updateRelevancyApplyData(applyTypeAddDto);
        }
    }

    @Override
    @Transactional
    public void deleteApplyTypeInfo(ApplyTypeDeleteDto applyTypeDeleteDto) {
        ApplyTypeAddDto addDto = new ApplyTypeAddDto();
        //逻辑删除应用类型主数据
        applyTypeMapper.deleteApplyTypeMain(applyTypeDeleteDto);
        for (String applyTypeCode : applyTypeDeleteDto.getApplyTypeCodes()) {
            addDto.setApplyTypeCode(applyTypeCode);
            addDto.setCompanyCode(applyTypeDeleteDto.getCompanyCode());
            addDto.setCreatePerson(applyTypeDeleteDto.getUpdatePerson());
            //清除原有应用类型和组织的关系
            applyTypeMapper.clearApplyTypeOrgInfo(addDto);
            //清除原有关联应用数据
            applyTypeMapper.clearRelevancyApplyData(addDto);
        }
        Result result = identFeignInterface.deleteStrategyRelation(applyTypeDeleteDto);
        log.info("Route=>ApplyTypeServiceImpl method=>deleteApplyTypeInfo 删除应用类型,远程删除相关联的策略数据");
        if (!result.isSuccess()) {
            log.error("Route=>ApplyTypeServiceImpl method=>deleteApplyTypeInfo 删除应用类型,远程删除相关联的策略数据失败!!!");
            throw new RuntimeException("删除应用类型,远程删除相关联的策略数据失败!!!");
        }
    }

    @Override
    public int verifyRelevancyApply(List<String> applyCodes, String applyTypeCode, String companyCode) {
        return applyTypeMapper.verifyRelevancyApply(applyCodes, applyTypeCode,companyCode);
    }

    @Override
    public List<IamApplyTypeBase> queryApplyTypeList(String companyCode){
        return applyTypeMapper.queryApplyTypeList(companyCode);
    }
}
